#include "spriteeditor.h"
#include <stdlib.h>
#include <stdio.h>

char * SpriteEditor::loadNewSpriteFile(const char * a_filename)
{
	FILE * pFile;
	char * fileData = 0;
	int read = -1;
	fopen_s(&pFile, a_filename, "rb");
	if (pFile)
	{
		// check to see if there is enough data to aquire a length
		if(fseek (pFile, 0, SEEK_END) == 0)
		{
			// grab the total file size
			long lSize = ftell(pFile);
			rewind (pFile);
			// allocate memory to contain the whole file:
			fileData = new char[lSize];
			// if the memory was allocated
			if (fileData)
			{
				// read the data into the file
				read = fread (fileData,1,lSize,pFile);
				// if the entire file was not read, mark as a failure.
				if (read != lSize)	read = -1;
			}
		}
		fclose(pFile);
	}
	if(fileData && read >= 0)
	{
		return fileData;
	}
	if(fileData)
		delete fileData;
	return 0;
}

void SpriteEditor::saveSpriteToBuffer(Sprite * s, TemplateVectorList<char> * a_buffer)
{
	const int bufferSize = 1024;
	char buffer[bufferSize];
	int numValues = 2;// clip count, animation count, //image count
	// first, calculate... we can afford a double-pass system.
	SAnimation * sa;	SFrame * sf;	SClip * sc;
	TemplateVector<ImageClip*> clips;
	// image descriptions
	TemplateVector<BitMaP*> images;
	TemplateVector<SRect> imageRequierments;
	// TODO
	TemplateVector<char*> imageDescription;
	numValues += s->getAnimationCount(); // frame count is one number per animation
	for(int a = 0; a < s->getAnimationCount(); ++a)
	{
		sa = s->getAnimation(a);
		numValues += 2*sa->getFrameCount(); // at least a delay and clip count per frame
		for(int f = 0; f < sa->getFrameCount(); ++f)
		{
			sf = sa->getFrame(f);
			numValues += 3*sf->getClipCount(); // clip id, x offset, y offset per clip
			for(int c = 0; c < sf->getClipCount(); ++c)
			{
				sc = sf->getClip(c);
				ImageClip * ic = sc->getClip();
				clips.addNoDuplicates(ic);
				int imageIndex = images.addNoDuplicates(ic->image);
				if(imageIndex >= imageRequierments.size())
				{
					imageRequierments.add(ic->clip);
					// TODO make method getImageDescription, and replace this empty description
					imageDescription.add("image");
//						numValues += 2;// width, height
				}
				else
				{
					imageRequierments.get(imageIndex).add(ic->clip);
				}
			}
		}
	}
	numValues += clips.size() * 5;	// imageID, x, y, w, h
	// now, print.
	sprintf_s(buffer, "short data[%d] = {\n", numValues);
	a_buffer->add(buffer, strlen(buffer));

	sprintf_s(buffer, "//%d,// image count\n",images.size());
	a_buffer->add(buffer, strlen(buffer));
	for(int i = 0; i < images.size(); ++i)
	{
		sprintf_s(buffer, "//\t%5d,\t%5d,// required WxH, imageID =%2d, %s\n", 
			imageRequierments.get(i).getWidth(), imageRequierments.get(i).getHeight(),
			i, imageDescription.get(i));
		a_buffer->add(buffer, strlen(buffer));
	}
	sprintf_s(buffer, "%d,\t// clip%s, referenced by clipID \n//imgID\tsrcX\tsrcY\twidth\theight\n",
		clips.size(),((clips.size()>1)?"s":""));
	a_buffer->add(buffer, strlen(buffer));
	for(int i = 0; i < clips.size(); ++i)
	{
		ImageClip * ic = clips.get(i);
		SRect * r = &ic->clip;
		sprintf_s(buffer, "%d,\t%d,\t%d,\t%d,\t%d,// clipID =%3d\n", 
			images.indexOf(ic->image), 
			r->getX(), r->getY(), r->getWidth(), r->getHeight(), i);
		a_buffer->add(buffer, strlen(buffer));
	}
	sprintf_s(buffer, "%d,// animation count\n", s->getAnimationCount());
	a_buffer->add(buffer, strlen(buffer));
	for(int a = 0; a < s->getAnimationCount(); ++a)
	{
		sa = s->getAnimation(a);
		sprintf_s(buffer, "%d,// animation[%d] frame count\n\t//delay\t#clip\tclipID\tdeltaX\tdeltaY\n", 
			sa->getFrameCount(), a);
		a_buffer->add(buffer, strlen(buffer));
		for(int f = 0; f < sa->getFrameCount(); ++f)
		{
			sf = sa->getFrame(f);
			sprintf_s(buffer, "\t%d,\t%d,", 
				sf->getDelay(), sf->getClipCount());
			a_buffer->add(buffer, strlen(buffer));
			for(int c = 0; c < sf->getClipCount(); ++c)
			{
				sc = sf->getClip(c);
				ImageClip * ic = sc->getClip();
				SPoint * offset = sc->getOffset();
				sprintf_s(buffer, "%s\t%d,\t%d,\t%d,\n", ((c>0)?"\t\t":""),
					clips.indexOf(ic), offset->getX(), offset->getY());
				a_buffer->add(buffer, strlen(buffer));
			}
		}
	}
	sprintf_s(buffer, "};\n");
	a_buffer->add(buffer, strlen(buffer));
}

/**
 * @param a_spriteFile contents of the file as a character array
 * @param a_out where to write the numeric data to
 */
void SpriteEditor::convertSpriteFileToNumberList(const char * a_spriteFile, TemplateVector<short> & a_out)
{
	int line = 1;
	int len = strlen(a_spriteFile);
	// find the first square bracket, thats where we figure out how many numbers we need
	int index = indexOfLetter(a_spriteFile, '[', 0);
	index++;// feed past the square bracket
	int expectedSize = parseInt(a_spriteFile, len, index);
	a_out.ensureCapacity(expectedSize);
	// find the first curly bracket, thats where data starts...
	index = indexOfLetter(a_spriteFile, '{', 0);
	index++;// feed past the curly bracket
	char c;
	char * errorString = 0;
	while(index < len && !errorString)
	{
		c = a_spriteFile[index++];
		switch(c)
		{
		// ignore /r, \n, ' ', ','
		case '\n':	line++;
		case '\r':	case ' ':	case '\t':	case ',':
			break;
		// if we see a "//", go just past the nearest new line
		case '/':
			c = a_spriteFile[index++];
			if(c == '/')
			{
				index = indexOfLetter(a_spriteFile, '\n', index);
			}
			else
			{
				errorString = "unrecognized comment?";
			}
			break;
		// the end curly bracket ends the list
		case '}':
			index = len;
			break;
		// digits and the negative sight trigger integer parsing
		case '0':	case '1':	case '2':	case '3':	case '4':	
		case '5':	case '6':	case '7':	case '8':	case '9':
		case '-':{
			int value = parseInt(a_spriteFile, len, --index);
			a_out.add((short)value);
			break;}
		default:
			errorString = "unexpected character";
		}
	}
	if(!errorString && a_out.size() != expectedSize)
	{
		errorString = "unexpected data count";
	}
	if(errorString)
	{
		printf("%s at line %d (%d/%d)\n", errorString, line, a_out.size(), expectedSize);
	}
}

bool SpriteEditor::saveMethod(const char * a_fileName)
{
	// load the sprite file into this buffer
	TemplateVectorList<char> buffer(512);
	saveSpriteToBuffer(m_sprite, &buffer);
	// save the buffer to the file system
	FILE * pFile;
	fopen_s(&pFile, a_fileName,"w");
	if (pFile!=NULL)
	{
		for(int i = 0; i < buffer.size(); ++i)
		{
			fputc(buffer.get(i),pFile);
		}
		fclose (pFile);

		const int BUFFER_SIZE = 1024;
		int nameSize = BUFFER_SIZE;
		char name[BUFFER_SIZE];
//		EditorPanel::getFilenameFromPath(a_fileName, name, nameSize);
		updateTabText(name);
		m_sprite->setName(name);
		setFileName(a_fileName);
		return true;
	}
	return false;
}

bool SpriteEditor::loadMethod(const char * a_path)
{
	TemplateVector<short> data;
	char * file = loadNewSpriteFile(a_path);
	if(file)
	{
		convertSpriteFileToNumberList(file, data);
		const int bufferSize = 255;
		char buffer[bufferSize];
		getFilenameFromPath(a_path, buffer, bufferSize);
		Sprite * sprite = new Sprite();
		sprite->set(buffer, 0, data.getRawList());
		setSprite(sprite);
//		updateTabText(buffer);
		delete file;
		return true;
	}
	return false;
}
